package org.wu.framework.lazy.orm.database.sql.expand.database.persistence.proxy;

import lombok.extern.slf4j.Slf4j;
import org.wu.framework.core.annotation.AnnotatedElementUtils;
import org.wu.framework.lazy.database.datasource.proxy.connection.LazyProxyConnection;
import org.wu.framework.lazy.orm.core.stereotype.proxy.ProxyLazyStrategicApproach;
import org.wu.framework.lazy.orm.database.lambda.dynamic.LazyDynamicDatasourceAdapter;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.LazySqlOperation;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.cure.CureAdapter;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.factory.LazyOperationProxyFactory;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.method.LazyOperationMethod;
import org.wu.framework.lazy.orm.database.sql.expand.database.persistence.translation.adapter.LazyTranslationAdapter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : Jia wei Wu
 * @version 1.0
 * describe : 自定义接口实现方法执行代理类 包含执行 DDL、DQL、DML
 * @date : 2020/6/25 下午11:19
 * @see LazyOperationProxyBeanAutoConfiguration#lazyOperationProxy(List, LazyDynamicDatasourceAdapter, CureAdapter, LazyTranslationAdapter)
 * @see LazyOperationProxyFactory
 * @see LazySqlOperation
 */
@Slf4j
public class LazyOperationProxy extends AbstractLazyOperationProxyInvocationHandler implements InvocationHandler {

    protected final ConcurrentHashMap<Class<? extends LazyOperationMethod>, LazyOperationMethod> LAZY_OPERATION_METHOD_MAP = new ConcurrentHashMap<>();

    private final List<LazyOperationMethod> lazyOperationMethods;

    private final LazyDynamicDatasourceAdapter lazyDynamicDatasourceAdapter;
    private final CureAdapter cureAdapter;// 治愈适配器
    /**
     * 跨表转译适配器
     */
    private final LazyTranslationAdapter lazyTranslationAdapter;

    /**
     * @param lazyOperationMethods         自定义数据库持久层操作方法
     * @param lazyDynamicDatasourceAdapter 动态数据源适配器
     * @param cureAdapter                  治愈工厂
     * @param lazyTranslationAdapter       数据库orm数据库转换适配器
     */
    public LazyOperationProxy(List<LazyOperationMethod> lazyOperationMethods, LazyDynamicDatasourceAdapter lazyDynamicDatasourceAdapter, CureAdapter cureAdapter, LazyTranslationAdapter lazyTranslationAdapter) {
        this.lazyOperationMethods = lazyOperationMethods;
        this.lazyDynamicDatasourceAdapter = lazyDynamicDatasourceAdapter;
        this.cureAdapter = cureAdapter;
        this.lazyTranslationAdapter = lazyTranslationAdapter;
    }

    /**
     * @param proxy     代理对象
     * @param method    代理方法
     * @param args      代理方法参数
     * @param retryTime 重试
     * @param throwable 异常
     * @param hasRetry  是否已经重试
     * @return 返回的执行结果
     * @throws Throwable 异常信息
     */
    @Override
    public Object doRetryInvoke(Object proxy, Method method, Object[] args, int retryTime, Throwable throwable, boolean hasRetry) throws Throwable {
        ProxyLazyStrategicApproach mergedAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, ProxyLazyStrategicApproach.class);
        if (null != mergedAnnotation) {
            LazyOperationMethod lazyOperationMethod = getLazyOperationMethod(mergedAnnotation.proxyClass());
            if (null == lazyOperationMethod) {
                throw new IllegalArgumentException("无法找到对应class ：【" + mergedAnnotation.proxyClass() + "】的代理实现");
            }
            try {
                Object execute = doInvoke(lazyOperationMethod, args);
                lazyTranslationAdapter.transformation(execute);
                return execute;
            } catch (Exception exception) {
                // 治愈表
                return cureAdapter.cure(this, proxy, method, args, retryTime, exception);
            }
        } else {
            if (method.getParameterCount() == 0) {
                return method.invoke(this, args);
            } else {
                return method.invoke(null, args);
            }
        }
    }


    /**
     * 获取不同的策略
     *
     * @param proxyClass class 名称
     * @return 策略
     */
    public LazyOperationMethod getLazyOperationMethod(Class<?> proxyClass) {
        if (LAZY_OPERATION_METHOD_MAP.isEmpty()) {
            lazyOperationMethods.forEach(lazyOperationMethod -> LAZY_OPERATION_METHOD_MAP.put(lazyOperationMethod.getClass(), lazyOperationMethod));
        }

        return LAZY_OPERATION_METHOD_MAP.get(proxyClass);
    }

    /**
     * 获取当前连接
     *
     * @return 数据当前连接
     */
    @Override
    LazyProxyConnection determineConnection() throws SQLException {
        return lazyDynamicDatasourceAdapter.determineConnection();
    }
}
